﻿/*///////////////////////////////////////////////////////////
TodoRoll.as
Ben Smith
2009
///////////////////////////////////////////////////////////*/

package com.bsmith.app.presentation 
{
	import com.bsmith.app.model.TodoAppState;
	import com.bsmith.app.model.TodoEvent;
	import com.bsmith.app.model.TodoItem;
	import com.bsmith.common.CustomEvent;
	import com.flashdynamix.motion.TweensyZero;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Point;
	
	/*===========================================================
	TodoRoll
	The todo roll displays all of the todo entries in the app.
	===========================================================*/
	public class TodoRoll extends Sprite
	{
		static public const EVENT_VIEW_UPDATED:String = "tdr.viewup";
		static private const ITEM_HEIGHT:int = 30;
		static private const ROLL_WIDTH:int = 300;
		static private const ROLL_ELEMENT_HEIGHT:int = 10;
		static private const FOOTER_HEIGHT:int = 24;
		static private const ROLL_ELEMENT_ROUNDING:int = 7;
		static private const ENTRY_TWEEN_TIME:Number = 0.4;
		
		private var _smcFooter:Sprite;
		private var _smcBG:Sprite;
		
		private var _color:uint = 0;			//Todo Roll color
		private var _sListType:String = null;	//Todo list type
		private var _aItemClips:Array = [];		//Item display clips
		
		/*-----------------------------------------------------------
		TodoRoll - ctor
		-----------------------------------------------------------*/
		public function TodoRoll(sListType:String, color:uint) 
		{
			_sListType = sListType;
			_color = color;
	
			createPresentation();
		}
		
		/*-----------------------------------------------------------
		createPresentation
		Creates the presentation for this roll
		-----------------------------------------------------------*/
		private function createPresentation():void
		{
			_smcBG = new Sprite;
			_smcBG.graphics.clear();
			_smcBG.graphics.beginFill(_color);
			_smcBG.graphics.drawRect(0, 0, ROLL_WIDTH, 1);
			this.addChild(_smcBG);
			
			_smcFooter = new Sprite;
			_smcFooter.graphics.clear();
			_smcFooter.graphics.beginFill(_color);
			_smcFooter.graphics.drawRoundRectComplex(0, 0, ROLL_WIDTH, FOOTER_HEIGHT, 0, 0, ROLL_ELEMENT_ROUNDING, ROLL_ELEMENT_ROUNDING);
			_smcFooter.y = _smcBG.height;
			this.addChild(_smcFooter);
		}
		
		/*-----------------------------------------------------------
		initialize
		Initializes roll listeners
		-----------------------------------------------------------*/
		public function initialize()
		{
			TodoAppState.instance.addTodoListEventCallback(_sListType, TodoEvent.NEW_TODO_ENTRY, addItem, false, 0, true);
			TodoAppState.instance.addTodoListEventCallback(_sListType, TodoEvent.REMOVE_TODO_ENTRY, removeItem, false, 0, true);
			TodoAppState.instance.addTodoListEventCallback(_sListType, TodoEvent.REORDER_TODO_ENTRIES, reorderItems, false, 0, true);
		}
		
		/*-----------------------------------------------------------
		reorderItems
		Reorders todo items
		-----------------------------------------------------------*/
		private function reorderItems(e:TodoEvent):void 
		{
			updateView();
		}
		
		/*-----------------------------------------------------------
		addItem
		Adds a new item to the roll
		-----------------------------------------------------------*/
		private function addItem(e:TodoEvent, item:TodoItem = null, forceUpdate:Boolean = true)
		{
			var mcItem:TodoEntry = e ? new TodoEntry(e.data.item) : new TodoEntry(item);
			mcItem.addEventListener(TodoEntry.EVENT_BEGIN_DRAG, onBeginEntryDrag, false, 0, true);
			mcItem.addEventListener(TodoEntry.EVENT_END_DRAG, onEndEntryDrag, false, 0, true);
			this.addChild(mcItem);
			_aItemClips.push(mcItem);
			mcItem.x = getEntryPositionByIndex(_aItemClips.length-1).x;
			mcItem.y =  getEntryPositionByIndex(_aItemClips.length - 1).y;
			if (forceUpdate)
				updateView();
		}
		
		/*-----------------------------------------------------------
		removeItem
		Removes an entry from the roll
		-----------------------------------------------------------*/
		private function removeItem(e:TodoEvent):void 
		{
			var mcItem:TodoEntry = _aItemClips[e.data.index];
			mcItem.removeEventListener(TodoEntry.EVENT_BEGIN_DRAG, onBeginEntryDrag);
			mcItem.removeEventListener(TodoEntry.EVENT_END_DRAG, onEndEntryDrag);
			_aItemClips.splice(e.data.index, 1);
			mcItem.release();
			this.removeChild(mcItem);
			updateView();
		}
		
		/*-----------------------------------------------------------
		onBeginEntryDrag
		Logic when user begins dragging entry
		-----------------------------------------------------------*/
		private function onBeginEntryDrag(e:CustomEvent):void 
		{
			var entry:TodoEntry = e.data.entry;
			this.addChild(entry);
		}
		
		/*-----------------------------------------------------------
		onEndEntryDrag
		Logic when user ends dragging entry
		-----------------------------------------------------------*/
		private function onEndEntryDrag(e:CustomEvent):void 
		{
			//Nothing...
		}
		
		/*-----------------------------------------------------------
		updateView
		Updates todo roll and moves items around
		-----------------------------------------------------------*/
		public function updateView()
		{
			_smcBG.height = getItems().length * ITEM_HEIGHT + 21;	
			_smcFooter.y = _smcBG.y + _smcBG.height;
			
			for (var i:int = 0; i < _aItemClips.length; ++i)
			{
				var mcItem:TodoEntry = _aItemClips[i];
				mcItem.setBright(i % 2 == 0)
				var targetPnt:Point = getEntryPositionByIndex(i);
				if (!mcItem.isDragging())
					TweensyZero.to(mcItem, {x:targetPnt.x, y:targetPnt.y}, ENTRY_TWEEN_TIME);
			}
			this.dispatchEvent(new Event(EVENT_VIEW_UPDATED));
		}
		
		/*-----------------------------------------------------------
		getEntryPositionByIndex
		Returns entry position by index
		-----------------------------------------------------------*/
		private function getEntryPositionByIndex(i:int):Point
		{
			return new Point(3, 30 + i * ITEM_HEIGHT );
		}
		
		/*###########################################################
		GETTERS AND SETTERS
		###########################################################*/
		public function getItems():Array { return TodoAppState.instance.getTodoList(_sListType).getItems(); }
		public function getClips():Array { return _aItemClips; }
		public function getListType():String { return _sListType; }
	}
}